#!/bin/bash

#
# This file is part of the batocera distribution (https://batocera.org).
# Copyright (c) 2025+.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# YOU MUST KEEP THIS HEADER AS IT IS
#

# A script to set the TDP for supported AMD APUs based on detected or pre-determine values.
# It allows a TDPWatt input and implicitly handles overclocking up to a safe ceiling.

log="/userdata/system/logs/amd-tdp.log"
TDP_INPUT="$1"

# --- Sanity Checks ---
if [[ "$(/usr/bin/ryzenadj -i)" =~ "unsupported model" ]]; then
  echo "Unsupported CPU for RyzenAdj. Aborting." >> "$log"
  exit 1
fi

# --- Device-Specific Configurations ---
declare -A tdp_ranges
tdp_ranges=(
    ["Loki_Zero"]="AYN Loki Zero;5;20"
    ["83E1"]="Lenovo Legion Go;5;30"
    ["AYANEO_2S"]="Ayaneo 2S;15;28"
    ["AIR_Plus"]="Ayaneo Air Plus;5;28"
    ["Jupiter"]="Steam Deck LCD;3;15"
    ["Galileo"]="Steam Deck OLED;3;15"
    ["ROG_Ally_RC71L_Action"]="ROG Ally;9;30"
    ["ROG_Ally_RC71L_RC71L"]="ROG Ally;9;30"
    ["ROG_Ally_RC71L"]="ROG Ally;9;30"
    ["ROG_Ally_X_RC72LA"]="ROG Ally X;9;30"
)

# Determine device's standard min/max TDP
TDP_MIN=5 # Default min fallback
BASE_TDP_MAX=35 # Default max fallback
APPLY_TEMP_LIMIT=0 # Only set 90c for found handhelds

device_model=$(batocera-model)

if [[ -v tdp_ranges["$device_model"] ]]; then
    IFS=';' read -r -a info <<< "${tdp_ranges[$device_model]}"
    TDP_MIN=${info[1]}
    BASE_TDP_MAX=${info[2]}
    APPLY_TEMP_LIMIT=1
    echo "Device: ${info[0]} detected. Standard range: ${TDP_MIN}W - ${BASE_TDP_MAX}W." >> "$log"
else
    SYSTEM_TDP=$(/usr/bin/batocera-settings-get system.cpu.tdp)
    if [ -n "$SYSTEM_TDP" ]; then
        BASE_TDP_MAX=$SYSTEM_TDP
        echo "Detected reported max of ${BASE_TDP_MAX}W." >> "$log"
    else
        echo "No system TDP defined." >> "$log"
        exit 1
    fi
fi

# --- TDP Calculation & Clamping ---

# Calculate the absolute overclocking ceiling (+20%)
OC_CEILING=$(awk -v max="$BASE_TDP_MAX" 'BEGIN {printf "%.0f\n", max * 1.20}')

# Use user input, or default to 15W if not provided
TDP=${TDP_INPUT:-15}
echo "User input requested: ${TDP}W." >> "$log"

# Clamp the values if needed
if (( TDP < TDP_MIN )); then
    echo "Request is below minimum. Clamping to ${TDP_MIN}W." >> "$log"
    TDP=$TDP_MIN
elif (( TDP > OC_CEILING )); then
    echo "Request exceeds overclock ceiling. Clamping to ${OC_CEILING}W." >> "$log"
    TDP=$OC_CEILING
fi

# --- Apply Settings ---
WATTS=$((TDP * 1000))
SLOW_WATTS=$((WATTS * 80 / 100)) # TODO: Rethink how amd tdp is applied between handhelds and everything else(if not handheld should porobably set all limits to same value)

if (( APPLY_TEMP_LIMIT )); then
    echo "Applying final TDP: ${TDP}W, Temp Limit: 90C" >> "$log"
else
    echo "Applying final TDP: ${TDP}W" >> "$log"
fi

cmd=(/usr/bin/ryzenadj
    --stapm-limit="$WATTS"
    --fast-limit="$WATTS"
    --slow-limit="$SLOW_WATTS"
)

# Only set temp limit for known handhelds
if (( APPLY_TEMP_LIMIT )); then
    cmd+=(--tctl-temp=90)
fi

if "${cmd[@]}"; then
    echo "Successfully set TDP to ${TDP}W." >> "$log"
else
    echo "ERROR: ryzenadj command failed. Power limits may not have been applied." >> "$log"
    exit 1
fi

echo "" >> "$log"
echo "*** ------------------------------------- ***" >> "$log"
echo "" >> "$log"

exit 0
